﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using ScottPlot.Plottables;
using ScottPlot.WPF;
using ServoDrivesLib.Controls;
using ServoDrivesLib.Model;
using ServoDrivesLibAbstract;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using System.Xml.Schema;
using 雷赛板卡上位机.Attributes;
using 雷赛板卡上位机.Services;
using ControlType = ServoDrivesLib.Model.ControlType;
using Timer = System.Timers.Timer;

namespace 雷赛板卡上位机.ViewModel
{
    public partial class AxisControlViewModel : BaseViewModel, IDisposable
    {

        private int count = 0;
        private AxisParam _param; // 轴参数对象
        private int axis; // 轴索引
        private IServoControl? servo; // 伺服控制接口
        private bool isCollection = false;
        private bool IsMousLeft = false;
        private Task? moveTask;
        private CancellationTokenSource cancellationTokenSource; // 用于取消任务的令牌源
        private CancellationTokenSource moveTokenSource;
        private VerticalLine? xMoveLine = null;
        private HorizontalLine? yMoveLine = null;
        public WpfPlotBase WpfPlot => wpfPlot;
        public bool IsStart = false;

        private readonly object _lock = new object();
        private readonly Stopwatch stopwatch = new Stopwatch();
        private readonly double segmentation = 16;
        private readonly Dispatcher dispatcher;
        private readonly ILogger<AxisControlViewModel> logger;
        private readonly ControlType controlType;
        private readonly int sleepTime = 100;
        private readonly Timer timer;
        private readonly Timer framTimer;
        private readonly DispatcherTimer outTextTimer;
        private readonly HybridDictionary dataStreamer;
        private readonly WpfPlotBase wpfPlot = new WpfPlotGL();
        private readonly VerticalLine[] xLine = new VerticalLine[2];
        private readonly HorizontalLine[] yLine = new HorizontalLine[2];
        private readonly StringBuilder buffer = new StringBuilder();



        [ObservableProperty]
        private double xPixel;
        [ObservableProperty]
        private double yPixel;
        [ObservableProperty]
        private double xDeviation;
        [ObservableProperty]
        private double yDeviation;
        [ObservableProperty]
        private string outText;
        public AxisControlViewModel(Dispatcher dispatcher, ILogger<AxisControlViewModel>? log, IConfiguration? configuration) : base()
        {
            try
            {
                sleepTime = int.Parse(configuration.GetRequiredSection("SleepTime").Value ?? "100");
            }
            catch
            {
                sleepTime = 100;
            }

            dataStreamer = new(10);
            this.dispatcher = dispatcher;
            _param = _param.CreateInit();

            this.logger = log ?? NullLogger<AxisControlViewModel>.Instance;
            controlType = ControlService.GetControlType();
            this.servo = App.GetService<CardControlManager>().Get(controlType.ToString())?.ServoControl;


            cancellationTokenSource = new CancellationTokenSource();

            timer = new Timer();
            timer.Elapsed += Timer_Tick;
            timer.Interval = TimeSpan.FromMicroseconds(sleepTime).TotalMilliseconds;
            timer.AutoReset = true;

            framTimer = new Timer();
            framTimer.Elapsed += FramTimer_Tick;
            framTimer.Interval = TimeSpan.FromMilliseconds(16).TotalMilliseconds;
            framTimer.AutoReset = true;

            outTextTimer = new DispatcherTimer(DispatcherPriority.DataBind);
            outTextTimer.Interval = TimeSpan.FromMilliseconds(32);
            outTextTimer.Tick += OutTextTimer_Tick;
            outTextTimer.Start();



            servo?.SetEquiv(axis, Unit);
            servo?.SetProFile(axis, 0, Speed, Acceleration, Deceleration, 0, Sramp);
            wpfPlot.Plot.Legend.IsVisible = true;
            wpfPlot.Plot.XLabel("time(s)");
            wpfPlot.Plot.HideGrid();
            wpfPlot.MouseMove += WpfPlot_MouseMove;
            wpfPlot.MouseDown += WpfPlot_MouseDown;

            timer.Start();
        }

        private void OutTextTimer_Tick(object? sender, EventArgs e)
        {
            OutText = buffer.ToString();
        }

        private void WpfPlot_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (!isCollection)
            {
                if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
                {

                    int pixelX = (int)e.MouseDevice.GetPosition(wpfPlot).X;
                    int pixelY = (int)e.MouseDevice.GetPosition(wpfPlot).Y;

                    var pixe = wpfPlot.Plot.GetCoordinates(pixelX, pixelY);

                    XPixel = pixe.X;
                    YPixel = pixe.Y;
                    // 获取当前轴范围
                    var xAxis = wpfPlot.Plot.Axes.AllGrids[0].XAxis.Range;
                    var yAxis = wpfPlot.Plot.Axes.AllGrids[0].YAxis.Range;

                    var xLength = (xAxis.Max - xAxis.Min) / segmentation;
                    var yLength = (xAxis.Max - xAxis.Min) / segmentation;
                    if (xLine[0] != null && xLine[1] != null)
                    {
                        if (Math.Abs(XPixel - xLine[0].X) <= xLength)
                        {
                            xMoveLine = xLine[0];
                        }
                        else if (Math.Abs(XPixel - xLine[1].X) <= xLength)
                        {
                            xMoveLine = xLine[1];
                        }
                    }

                    if (yLine[0] != null && yLine[1] != null)
                    {
                        if (Math.Abs(YPixel - yLine[0].Y) <= yLength)
                        {
                            yMoveLine = yLine[0];
                        }
                        else if (Math.Abs(YPixel - yLine[1].Y) <= yLength)
                        {
                            yMoveLine = yLine[1];
                        }
                    }

                }
            }
        }


        private void WpfPlot_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (!isCollection)
            {
                int pixelX = (int)e.MouseDevice.GetPosition(wpfPlot).X;
                int pixelY = (int)e.MouseDevice.GetPosition(wpfPlot).Y;

                var pixe = wpfPlot.Plot.GetCoordinates(pixelX, pixelY);

                XPixel = pixe.X;
                YPixel = pixe.Y;

                switch (e.LeftButton)
                {
                    case System.Windows.Input.MouseButtonState.Pressed:


                        // 获取当前轴范围
                        var xAxis = wpfPlot.Plot.Axes.AllGrids[0].XAxis.Range;
                        var yAxis = wpfPlot.Plot.Axes.AllGrids[0].YAxis.Range;
                        if (xMoveLine != null)
                        {
                            wpfPlot.UserInputProcessor.Disable();
                            XDeviation = UpdateReferenceLine(xMoveLine, XPixel, xAxis.Min, xAxis.Max, segmentation);
                        }
                        if (yMoveLine != null)
                        {
                            wpfPlot.UserInputProcessor.Disable();
                            YDeviation = UpdateReferenceLine(yMoveLine, YPixel, yAxis.Min, yAxis.Max, segmentation * 2);
                        }
                        if (xLine[0] != null && xLine[1] != null)
                        {
                            XDeviation = xLine[0].X - xLine[1].X;
                        }
                        if (yLine[0] != null && yLine[1] != null)
                        {
                            YDeviation = yLine[0].Y - yLine[1].Y;
                        }
                        break;
                    case System.Windows.Input.MouseButtonState.Released:
                        wpfPlot.UserInputProcessor.Enable();
                        IsMousLeft = false;
                        xMoveLine = null;
                        yMoveLine = null;
                        break;
                }

            }
        }

        private void FramTimer_Tick(object? sender, EventArgs e)
        {
            if (IsStart)
            {
                foreach (DictionaryEntry i in dataStreamer)
                {
                    if (i.Value is DataLogger data)
                    {
                        if (data.HasNewData)
                        {
                            wpfPlot.Refresh();
                        }
                    }
                }
            }
        }

        private async void Timer_Tick(object? sender, EventArgs e)
        {
            count++;
            if (IsStart)
            {
                double pos = double.NaN; // 用于存储读取的值
                double speed = double.NaN;
                int status = 0;
                int error = 0;
                int moveStatus = 0;
                // 读取编码器单位值
                servo?.GetEncoderUnit(axis, ref pos);
                servo?.GetAxisSpeed(axis, ref speed);
                servo?.GetAxisStatus(axis, ref status);
                servo?.GetAxisError(axis, ref error);
                moveStatus = servo?.GetAxisMoveStatus(axis) ?? 0;

                //示波器添加数据
                if (isCollection)
                {
                    var p = dataStreamer["Position"] as DataLogger;
                    var s = dataStreamer["Speed"] as DataLogger;
                    var tick = stopwatch.Elapsed.TotalSeconds;
                    p?.Add(tick, pos);
                    s?.Add(tick, speed);
                }

                //更新界面数据
                await this.dispatcher.InvokeAsync(() =>
                {
                    if (!cancellationTokenSource
                    .IsCancellationRequested)
                    {
                        FeedbackPosition = pos;
                        FeedbackSpeed = speed;
                        AxisStatus = status;
                        AxisError = error;
                        AxisMoveState = moveStatus;
                    }
                }, DispatcherPriority.DataBind, cancellationTokenSource.Token);
            }
        }

        // 设置轴索引
        public int AxisIndex
        {
            set => axis = value;
        }
        [CardRange(ControlType.Leisai, double.MaxValue, double.MinValue, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        [CardRange(ControlType.ZMonition, double.MaxValue, double.MinValue, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        // 等效单位属性
        public double Unit
        {
            get => _param.Unit;
            set
            {
                SetProperty(ref _param.Unit, value);
                _param.Unit = value;
            }
        }

        // 位置属性
        public double Position
        {
            get => _param.Position;
            set
            {
                SetProperty(ref _param.Position, value);
                _param.Position = value;
            }
        }
        [CardRange(ControlType.Leisai, 10000, 0, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        [CardRange(ControlType.ZMonition, 10000, 0, ErrorMessage = "输入数值需要{0}~{1}在之间")]

        // 速度属性
        public double Speed
        {
            get => _param.Speed;
            set
            {
                SetProperty(ref _param.Speed, value);
                _param.Speed = value;
            }
        }

        // 加速度属性
        [CardRange(ControlType.Leisai, 100, 0.0001, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        [CardRange(ControlType.ZMonition, 10000, 0, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        public double Acceleration
        {
            get => _param.Acceleration;
            set
            {
                SetProperty(ref _param.Acceleration, value, true);
                _param.Acceleration = value;
            }
        }

        [CardRange(ControlType.Leisai, 100, 0.0001, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        [CardRange(ControlType.ZMonition, 10000, 0, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        // 减速度属性
        public double Deceleration
        {
            get => _param.Deceleration;
            set
            {
                SetProperty(ref _param.Deceleration, value, true);
                _param.Deceleration = value;
            }
        }

        [CardRange(ControlType.Leisai, 100, 0.0001, ErrorMessage = "输入数值需要{0}~{1}在之间")]
        [CardRange(ControlType.ZMonition, 250, 0.0001, ErrorMessage = "输入数值需要{0}~{1}在之间")]

        // S形曲线属性
        public double Sramp
        {
            get => _param.Sramp;
            set
            {
                SetProperty(ref _param.Sramp, value, true);
                _param.Sramp = value;
            }
        }

        // 反馈位置属性
        public double FeedbackPosition
        {
            get => _param.FeedbackPosition;
            set
            {
                SetProperty(ref _param.FeedbackPosition, value);
                _param.FeedbackPosition = value;
            }
        }

        // 反馈速度属性
        public double FeedbackSpeed
        {
            get => _param.FeedbackSpeed;
            set
            {
                SetProperty(ref _param.FeedbackSpeed, value);
                _param.FeedbackSpeed = value;
            }
        }

        public int AxisMoveState
        {
            get => (int)_param.AxisMoveStatus;
            set
            {
                int tmp = (int)_param.AxisMoveStatus;
                SetProperty(ref tmp, value);
                _param.AxisMoveStatus = tmp;
            }
        }
        // 轴状态属性
        public int AxisStatus
        {
            get => (int)_param.AxisStatus;
            set
            {
                SetProperty(ref _param.AxisStatus, value);
                _param.AxisStatus = value;
            }
        }

        public bool IsAxisError
        {
            get => AxisError != 0;
        }
        // 轴错误属性
        public int AxisError
        {
            get => (int)_param.AxisError;
            set
            {
                SetProperty(ref _param.AxisError, value);
                OnPropertyChanging(nameof(IsAxisError));
                _param.AxisError = value;
            }
        }

        // 运动类型属性
        public AxisMoveType MoveType
        {
            get => _param.MoveType;
            set
            {
                SetProperty(ref _param.MoveType, value);
                _param.MoveType = value;
            }
        }

        // 启用轴命令
        [RelayCommand]
        void Enable()
        {
            // 停止当前轴的所有运动（确保启用前处于静止状态）
            AxisMoveStop();

            // 清除伺服轴的错误状态（若存在错误需先恢复）
            servo?.ClearAxisError(axis);

            // 设置轴的等效参数（Unit为预设单位或倍率）
            servo?.SetEquiv(axis, Unit);

            // 配置轴的运动参数（关键参数说明）：
            // MinSpeed - 最小速度
            // Speed - 目标速度
            // Acceleration - 加速度
            // Deceleration - 减速度
            // StopSpeed - 停止速度
            // Sramp - 速度斜坡时间（软启动参数）
            servo?.SetProFile(axis, 0, Speed, Acceleration, Deceleration, 0, Sramp);

            // 等待100ms确保参数配置完成（伺服可能需要响应时间）
            Thread.Sleep(100);

            // 启用伺服轴（物理使能，允许电机通电并执行运动）
            servo?.SetAxisEnable(axis);

        }

        // 禁用轴命令
        [RelayCommand]
        void Disable()
        {
            AxisMoveStop();
            servo?.SetAxisDisable(axis); // 禁用轴
        }

        [RelayCommand]
        void CollectionClick()
        {
            // 禁用用户输入交互（防止采集期间误操作图表）
            wpfPlot.UserInputProcessor.Disable();

            // 清空图表当前所有数据和图形元素（准备新采集数据）
            wpfPlot.Plot.Clear();

            // 创建位置和速度两个数据记录器（用于实时采集坐标数据）
            var pos = WpfPlot.Plot.Add.DataLogger();
            var speed = WpfPlot.Plot.Add.DataLogger();

            // 设置图例显示名称（区分不同数据类型）
            pos.LegendText = "Position";
            speed.LegendText = "Speed";

            // 将数据记录器注册到数据流容器中
            // （确保每个数据类型都有独立的记录器）
            if (dataStreamer.Contains("Position"))
            {
                dataStreamer["Position"] = pos; // 替换旧记录器（可能已存在时更新）
            }
            else
            {
                dataStreamer.Add("Position", pos); // 不存在则新增
            }

            if (dataStreamer.Contains("Speed"))
            {
                dataStreamer["Speed"] = speed; // 同理处理速度记录器
            }
            else
            {
                dataStreamer.Add("Speed", speed);
            }

            // 如果当前未处于采集状态，则调整数据记录器的可视窗口
            // （可能用于初始化视图范围或滑动窗口）
            if (!isCollection)
            {
                foreach (DictionaryEntry item in dataStreamer)
                {
                    if (item.Value is DataLogger logger)
                    {
                        logger.ViewSlide(5); // 调整可视区域（参数5可能表示窗口长度）
                    }
                }
            }

            // 启动帧定时器（用于定时更新数据采集）
            framTimer?.Start();

            // 设置采集状态为"开始"
            isCollection = true;

            // 重置并启动计时器（记录采集持续时间）
            stopwatch?.Restart();
        }

        [RelayCommand]
        void StopCollectionClick()
        {
            // 停止帧定时器（使用空条件运算符防止空引用异常）
            framTimer?.Stop();

            // 设置采集状态为"停止"（用于后续条件判断）
            isCollection = false;

            // 停止计时器（记录采集时间）
            stopwatch?.Stop();

            // 遍历数据流容器中的所有数据记录器
            foreach (DictionaryEntry item in dataStreamer)
            {
                if (item.Value is DataLogger logger)
                {
                    // 将数据记录器中的坐标数据转换为信号曲线并添加到图表
                    var s = wpfPlot.Plot.Add.SignalXY(
                        logger.Data.Coordinates.Select(c => c.X).ToArray(),  // 提取X坐标数组
                        logger.Data.Coordinates.Select(c => c.Y).ToArray(),  // 提取Y坐标数组
                        logger.LineColor);                                   // 使用预设颜色

                    // 设置图例显示名称（使用字典键作为标识）
                    s.LegendText = item.Key.ToString();

                    // 移除原始数据记录器对象（释放资源或更新图表显示）
                    wpfPlot.Plot.Remove(logger);
                }
            }

            // 启用用户输入交互（采集期间可能禁用了部分交互功能）
            wpfPlot.UserInputProcessor.Enable();
        }
        [RelayCommand]
        void YAxisCursor()
        {
            // 如果当前处于集合模式则直接返回（避免重复绘制）
            if (isCollection) return;

            // 清除之前绘制的所有水平参考线
            foreach (var i in yLine)
            {
                wpfPlot.Plot.Remove(i);
            }

            // 获取当前Y轴的最小值和最大值
            double min = wpfPlot.Plot.Axes.AllGrids[0].YAxis.Range.Min;
            double max = wpfPlot.Plot.Axes.AllGrids[0].YAxis.Range.Max;

            // 计算Y轴范围的1/16作为基准单位长度
            double length = (max - min) / 16;

            // 在Y轴最小值上方1个单位位置添加第一条水平线，并设置标签
            yLine[0] = wpfPlot.Plot.Add.HorizontalLine(min + length);
            yLine[0].Text = "y1";

            // 在第一条线基础上增加8个单位长度的位置添加第二条水平线，并设置标签
            // （总跨度为当前Y轴范围的1/2）
            yLine[1] = wpfPlot.Plot.Add.HorizontalLine(yLine[0].Y + (8 * length));
            yLine[1].Text = "y2";
            YDeviation = yLine[0].Y - yLine[1].Y;

            // 刷新图表以显示新绘制的参考线
            wpfPlot.Refresh();
        }
        [RelayCommand]
        void XAxisCursor()
        {
            if (isCollection) return;
            foreach (var i in xLine)
            {
                wpfPlot.Plot.Remove(i);
            }
            double min = wpfPlot.Plot.Axes.AllGrids[0].XAxis.Range.Min;
            double max = wpfPlot.Plot.Axes.AllGrids[0].XAxis.Range.Max;
            double length = (max - min) / 16;
            xLine[0] = wpfPlot.Plot.Add.VerticalLine(min + length);
            xLine[0].Text = "x1";
            xLine[1] = wpfPlot.Plot.Add.VerticalLine(xLine[0].X + (8 * length));
            xLine[1].Text = "x2";
            XDeviation = xLine[0].X - xLine[1].X;

            wpfPlot.Refresh();

        }

        [RelayCommand]
        void AutoDisplay()
        {
            if (!isCollection)
            {
                wpfPlot.Plot.Axes.AutoScaleX();
                wpfPlot.Plot.Axes.AutoScaleY();
                wpfPlot.Refresh();
            }

        }
        [RelayCommand]
        void CloseXYAxisCursor()
        {
            if (isCollection) return;
            foreach (var i in xLine) { wpfPlot.Plot.Remove(i); }
            foreach (var item in yLine)
            {
                wpfPlot.Plot.Remove(item);
            }
            wpfPlot.Refresh();
        }
        // 开始运动命令
        [RelayCommand]
        void StartMove()
        {
            servo?.SetEquiv(axis, Unit);
            servo?.SetProFile(axis, 0, Speed, Acceleration, Deceleration, 0, Sramp);
            switch (MoveType)
            {
                case AxisMoveType.Absolute:
                    servo?.MoveAxisAbs(axis, Position);
                    break;
                case AxisMoveType.Relative:
                    servo?.MoveAxis(axis, Position);
                    break;
                case AxisMoveType.Home:
                    servo?.SetHomeMove(axis);
                    break;
                case AxisMoveType.Loop:
                    if (moveTask != null)
                    {
                        if (moveTask.Status == TaskStatus.Running)
                        {
                            return;
                        }
                    }
                    moveTokenSource = new CancellationTokenSource();
                    moveTask = new Task(async () =>
                    {
                        if (AxisStatus != 0x04) { MessageBox.Show("请先使能轴", "警告"); return; }
                        while (moveTokenSource.IsCancellationRequested == false)
                        {
                            servo?.MoveAxisAbs(axis, Position);
                            await Task.Run(async () =>
                            {
                                do
                                {
                                    await Task.Delay(TimeSpan.FromMicroseconds(sleepTime));
                                } while (AxisMoveState == 0);
                            });
                            await Task.Delay(TimeSpan.FromMicroseconds(sleepTime * 2));
                            servo?.MoveAxisAbs(axis, 0);
                            await Task.Run(async () =>
                            {
                                do
                                {
                                    await Task.Delay(TimeSpan.FromMicroseconds(sleepTime));
                                } while (AxisMoveState == 0);
                            });
                            await Task.Delay(TimeSpan.FromMicroseconds(sleepTime * 2));
                        }

                    }, moveTokenSource.Token);
                    moveTask.Start();
                    break;
            }
        }

        // 停止运动命令
        [RelayCommand]
        void StopMove()
        {
            moveTokenSource?.Cancel();
            servo?.MoveStop(axis);
            // 待实现
        }


        void AxisMoveStop()
        {
            if (moveTokenSource != null)
            {
                if (!moveTokenSource.IsCancellationRequested)
                {
                    moveTokenSource.Cancel();
                }
                if (moveTask.Status == TaskStatus.Running)
                {
                    Task.WaitAll(moveTask);
                }
            }
        }


        // 释放资源
        public void Dispose()
        {
            if (!cancellationTokenSource.IsCancellationRequested)
            {
                cancellationTokenSource?.Cancel(); // 取消任务
            }
            if (moveTokenSource is not null)
            {
                if (!moveTokenSource.IsCancellationRequested)
                {
                    moveTokenSource?.Cancel();
                }
            }
            timer?.Stop();
            framTimer?.Stop();
            timer?.Close();
            framTimer?.Close();
            stopwatch?.Dispose();
            moveTask?.Wait();
            cancellationTokenSource?.Dispose();
            moveTokenSource?.Dispose();
            GC.Collect();
        }
        private double UpdateReferenceLine(AxisLine lines, double pixelValue,
        double min, double max, double segmentationCount)
        {

            if (lines is null) return 0;
            double ret = 0;
            double length = (max - min) / segmentationCount;
            if (lines is VerticalLine vertical)
            {
                if (Math.Abs(vertical.X - pixelValue) < length)
                {
                    vertical.X = pixelValue;
                }
            }
            else if (lines is HorizontalLine horizontal)
            {
                if (Math.Abs(horizontal.Y - pixelValue) < length)
                {
                    horizontal.Y = pixelValue;
                }
            }


            return ret;
        }

        public override void AddText(object value)
        {
            if (value is null) return;
            if (value is not string str) return;
            lock (_lock) { buffer.AppendLine(str); }
            OutText = buffer.ToString();
        }
        public override void ClearText(object value)
        {
            if (value is null) return;
            if (value is not string str) return;
            lock (_lock)
            {
                buffer.Replace($"{str}{Environment.NewLine}", "");
            }
            OutText = buffer.ToString();
        }
        protected override void OnActivated()
        {
            Messenger.Register<AxisControlViewModel, ValueChangedMessage<bool>, string>(this, "MenuClose", (r, m) =>
            {
                if (m.Value)
                {
                    r.Dispose();
                }
            });
        }
    }
}